using System.Collections.Generic;
using System.Text;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine; 

namespace XFFSM
{



    /// <summary>
    /// RuntimeFSMController 运行时的示例
    /// </summary>
    public class RuntimeFSMControllerInstance
    {

        public string name;

        public string layerName;

        public RuntimeFSMController RuntimeFSMController;

        // 所有的参数
        internal Dictionary<int, FSMParameterData> parameters = new Dictionary<int, FSMParameterData>();

        [Tooltip("参数的默认值")]
        internal Dictionary<int, float> parameter_default = new Dictionary<int, float>();
        
        // 所有的状态
        internal Dictionary<string, FSMStateNode> states = new Dictionary<string, FSMStateNode>();

        internal List<FSMTransition> transitions = new List<FSMTransition>();

        // 默认状态
        internal FSMStateNode defaultState { get; private set; } = null;

        private Dictionary<string, FSMStateNode> current_states = new Dictionary<string, FSMStateNode>();

        private List<FSMStateNode> current_states_array = new List<FSMStateNode>();

        // 当前的过渡
        public FSMTransition currentTransition { get; private set; } = null;

        public FSMController FSMController { get; private set; }

        /// <summary>
        /// 状态切换计数(为了避免状态切换进入死循环)
        /// </summary>
        private Dictionary<string, int> state_count = new Dictionary<string, int>();

        /// <summary>
        /// 当前的帧数
        /// </summary>
        private int currentSeconds = -1;

        /// <summary>
        /// 记录Trigger触发的次数
        /// </summary>
        private Dictionary<int, int> trigger_count = new Dictionary<int, int>();

        private List<int> trigerKeys = new List<int>();

        public bool Started { get; private set; } = false;


        public RuntimeFSMControllerInstance(RuntimeFSMController runtimeFSMController, FSMController controller, string layerName)
        {
            FSMController = controller;
            // 把数据复制一份
            if (runtimeFSMController == null) return;
            name = runtimeFSMController.name;
            // 默认不执行任何状态
            current_states.Clear();

            RuntimeFSMController = GameObject.Instantiate(runtimeFSMController);
#if UNITY_EDITOR
            RuntimeFSMController.originGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(runtimeFSMController));
#endif
            RuntimeFSMController.name = runtimeFSMController.name;
            // 参数
            parameters.Clear();
            for (int i = 0; i < RuntimeFSMController.parameters.Count; i++)
            {
                FSMParameterData data = RuntimeFSMController.parameters[i];

                int name_hash = FSMController.StringToHash(data.name);

                if (parameters.ContainsKey(name_hash))
                    continue;
                data.nameHash = name_hash;

                data.onValueChange = null;
                parameters.Add(name_hash, data);
                parameter_default.Add(name_hash, data.Value);
            }

            // 状态
            states.Clear();
            for (int i = 0; i < RuntimeFSMController.states.Count; i++)
            {
                FSMStateNodeData stateData = RuntimeFSMController.states[i];
                FSMStateNode state = new FSMStateNode(stateData, this);

                if (states.ContainsKey(stateData.name)) continue;

                if (stateData.defaultState && stateData.BaseLayer())
                {
                    defaultState = state;
                }

                states.Add(stateData.name, state);
            }
            // 过渡
            transitions.Clear();
            foreach (var item in runtimeFSMController.transitions)
            {
                FSMTransition transition = new FSMTransition(this, item);
                transitions.Add(transition);
            }

            Started = false;
            this.layerName = layerName;
        }


        // 启动
        public void StartUp()
        { 
            Started = true;
            // 找到默认状态 切换
            SwitchState(defaultState, null);
        }

        public void Close()
        {
            // 切换到空状态 (当切换到空状态之后 就没有办法通过参数来切换状态)
            // 因为在判断条件是否满足时 会查询当前状态 如果当前状态为空 会直接return false;
            SwitchState(null, null);
            // 设置为非启动状态
            Started = false;
            // 重置参数
            ResetParamter();
        }
        internal void SwitchState(FSMStateNode state, FSMTransition transition)
        {
            //if (!Started) return;
            
            int second = Mathf.FloorToInt(Time.time);

            if (second != currentSeconds)
            {
                currentSeconds = second;
                state_count.Clear(); // 清空状态
            }
            // 添加状态
            if (state != null)
                AddStateCount(state.data.name);

            string parent = state != null ? state.data.Parent : string.Empty;

            // 退出当前状态
            ExitState(parent, state);
            EnterState(state);

            currentTransition = transition;

            // 检测当前状态是否有已经满足的条件 
            CheckConditionAndSwitch();
        }


        private void CheckConditionAndSwitch()
        {
            // 检测当前的状态是否有已经满足条件的过渡
            foreach (var item in transitions)
            {
                // 检测条件是否满足
                if (item.CheckConditionAndSwitch())
                    break;
            }
        }

        private void ExitState(string parent, FSMStateNode nextState)
        {
            if (!current_states.ContainsKey(parent)) return;
            if (current_states[parent] == null) return;

            FSMStateNode currentState = current_states[parent];

            if (nextState != null)
                currentState.nextState = nextState.data.name;

            if (nextState != null && nextState.data.CompareParent(currentState.data))
                nextState.lastState = currentState.data.name;

            if (nextState != null)
                nextState.nextState = string.Empty;  // 把下一个状态的值设置为空
            currentState.OnExit();

            // 移除状态
            current_states.Remove(parent);

            // 判断一下当前状态是否子状态机
            if (currentState.data.isSubStateMachine)
            {
                // 把子状态也退出掉
                ExitState(currentState.data.name, nextState);
            }
        }

        private void EnterState(FSMStateNode state)
        {
            if (state == null) return;

            string parent = state.data.Parent;

            if (current_states.ContainsKey(parent))
                current_states[parent] = state;
            else
                current_states.Add(parent, state);

            state?.OnEnter();
            // 触发事件
            FSMController.onStateChange?.Invoke(RuntimeFSMController.name, state.data.name);

            // 判断是否有子状态机
            if (state.data.isSubStateMachine)
            {
                // 进入到子状态机的默认状态
                FSMStateNodeData data = RuntimeFSMController.GetDefaultStateNodeData(state.data.name);
                if (data != null && states.ContainsKey(data.name))
                    EnterState(states[data.name]);
            }

        }
  
        public void SetBool(int name_hash, bool v)
        {
            SetParamter(name_hash, v ? 1 : 0, ParameterType.Bool);
        }
  
        public void SetFloat(int name_hash, float v)
        {
            SetParamter(name_hash, v, ParameterType.Float);
        }
 

        public void SetInt(int name_hash, int v)
        {
            SetParamter(name_hash, v, ParameterType.Int);
        }
         

        public void SetTrigger(int name) 
        {
            FSMParameterData parameter;
            if (parameters.TryGetValue(name, out parameter))
            {
                if (parameter.parameterType != ParameterType.Trigger)
                    return;

                if (parameter.value == 1)
                {
                    if (trigger_count.ContainsKey(name))
                        trigger_count[name]++;
                    else
                        trigger_count.Add(name, 1);
                }
                else
                {
                    SetParamter(name, 1, ParameterType.Trigger);
                }

            }
        }

        /// <summary>
        /// 当Trigger触发后还原trigger
        /// </summary>
        /// <param name="name"></param>
        internal void ClearTrigger(int name)
        {
            SetParamter(name, 0, ParameterType.Trigger);
        }

        //public void ResetTrigger(string name)
        //{
        //    ResetTrigger(FSMController.StringToHash(name));
        //}

        public void ResetTrigger(int name)
        {
            if (trigger_count.ContainsKey(name))
                trigger_count[name] = 0;
            ClearTrigger(name);
        }
          
        private void SetParamter(int name, float v, ParameterType type) 
        {
            FSMParameterData parameter;
            if (parameters.TryGetValue(name, out parameter))
            {
                if (parameter.parameterType == type)
                    parameter.Value = v;
            }
        }


        //internal float GetParamter(string name)
        //{ 
        //    return GetParamter(FSMController.StringToHash(name));
        //}

        internal float GetParamter(int name)
        {
            FSMParameterData parameter;
            if (parameters.TryGetValue(name, out parameter))
                return parameter.value;
            return 0;
        }

        internal int GetTriggerCount(string name)
        { 
            return GetTriggerCount(FSMController.StringToHash(name));
        }

        internal int GetTriggerCount(int name)
        {

            if (trigger_count.ContainsKey(name))
                return trigger_count[name];

            return 0;
        }


        public void Update()
        {

            current_states_array.Clear();

            foreach (var item in current_states.Keys)
            {
                if (current_states[item] == null) continue;
                current_states_array.Add(current_states[item]);
            }

            foreach (var item in current_states_array)
            {
                if (!item.isRuning) continue;
                item.OnUpdate();
            }

            // 更新Trigger
            UpdateTrigger();
        }

        public void LateUpdate()
        {
            current_states_array.Clear();

            foreach (var item in current_states.Keys)
            {
                if (current_states[item] == null) continue;
                current_states_array.Add(current_states[item]);
            }

            foreach (var item in current_states_array)
            {
                if (!item.isRuning) continue;
                item.OnLateUpdate();
            }
        }

        public void FixedUpdate()
        {
            current_states_array.Clear();

            foreach (var item in current_states.Keys)
            {
                if (current_states[item] == null) continue;
                current_states_array.Add(current_states[item]);
            }

            foreach (var item in current_states_array)
            {
                if (!item.isRuning) continue;
                item.OnFixedUpdate();
            }
        }

        /// <summary>
        /// 添加计数
        /// </summary>
        /// <param name="stateName"></param>
        private void AddStateCount(string stateName)
        {
            if (state_count.ContainsKey(stateName))
                state_count[stateName]++;
            else
                state_count.Add(stateName, 0);

            if (state_count[stateName] > 30)
            {
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.Append("游戏物体:").Append(FSMController.gameObject.name)
                    .Append("状态机:").Append(this.RuntimeFSMController.name).Append("检测到状态:");
                foreach (var item in state_count.Keys)
                {
                    if (state_count[item] >= 29)
                    {
                        stringBuilder.Append(item).Append(",");
                    }
                }
                stringBuilder.Remove(stringBuilder.Length - 1, 1);
                stringBuilder.Append("之间频繁切换,请检查状态之间的过渡是否同时满足?请设置合理的状态切换条件!");
                state_count.Clear();
                throw new System.Exception(stringBuilder.ToString());
            }
        }


        private void UpdateTrigger()
        {
            // 更新Trigger
            foreach (var item in trigger_count.Keys)
            {
                if (!trigerKeys.Contains(item))
                    trigerKeys.Add(item);
            }

            foreach (var item in trigerKeys)
            {
                if (!trigger_count.ContainsKey(item))
                    continue;
                if (trigger_count[item] > 0 && GetParamter(item) == 0)
                {
                    SetParamter(item, 1, ParameterType.Trigger);
                    trigger_count[item]--;
                    if (trigger_count[item] < 0)
                        trigger_count[item] = 0;
                }
            }
        }

        public FSMStateNode GetCurrentState(string parent)
        {

            if (current_states.ContainsKey(parent))
                return current_states[parent];
            return null;
        }
        internal void ResetParamter()
        {
            foreach (var item in parameter_default.Keys)
            {
                FSMParameterData parameter;
                if (parameters.TryGetValue(item, out parameter))
                {
                    parameter.Value = parameter_default[item];
                }
            }
        }
    }
}